﻿----------------
-- setting up --
----------------

function callClientFunction ( funcname, ... ) 
	local arg = { ... } 
	if ( arg [ 1 ] ) then
		for key, value in next, arg do arg [ key ] = tonumber ( value ) or value end
	end
	loadstring ( "return "..funcname ) () ( unpack ( arg ) ) 
end
addEvent ( "onServerCallsClientFunction", true ) 
addEventHandler ( "onServerCallsClientFunction", resourceRoot, callClientFunction ) 

function callServerFunction ( funcname, ... )
    local arg = { ... }
    if ( arg [ 1 ] ) then
        for key, value in next, arg do
            if ( type ( value ) == "number" ) then arg [ key ] = tostring ( value ) end
        end
    end
    -- If the serverside event handler is not in the same resource, replace 'resourceRoot' with the appropriate element
    triggerServerEvent ( "onClientCallsServerFunction", resourceRoot , funcname, unpack ( arg ) )
end

function math.round ( number, decimals )
	if number and type ( number ) == "number" then
		decimals = decimals or 0
		local factor = 10 ^ decimals
		return tonumber ( ( "%." .. decimals .. "f" ):format ( number ) )
	end
end

function announce ( msgType )
	if msgType == "noVeh" then
		outputChatBox ( "Musisz być w #9696ffpojeździe#6464ff!", 100, 100, 255, true )
	elseif msgType == "noElem" then
		outputChatBox ( "Nie wybrałeś #9696ffelementu#6464ff!", 100, 100, 255, true )
	end
end

function commaToDot ( str )
	local str = string.gsub ( str, ",", "." )
	return tonumber ( str )
end

do -- setting vars
	guiSetInputMode ( "no_binds_when_editing" )
	enabled = false
	thePlayer = getLocalPlayer ()
	pos = 0.1
	rot = 15
	posrot = { x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0 }
	theElement = nil
	theElementName = nil
	gridListElements = {}
	mouseBool = false
	copyBool = false
	copyElementName = nil
	isSideShown = false
	autoRefreshBool = false
	mode = 0
	modeLabelText = {
		"Podaj ID, by stworzyć Peda, Obiekt lub Pojazd. Podaj nazwę pojazdu, by stworzyć Pojazd.", -- creator
		"Podaj liczbę od 0 do 255, by ustawić widzialność.\nZnaczenie kolorów:\nIm bardziej niebieski, tym mniej widoczny;\nBiały - w pełni widoczny\nCiemny niebieski - niewidoczny", -- alpha
		"Podaj liczbę większą od 0, by ustawić nową skalę (tylko dla obiektów).\nZnaczenie kolorów:\nCzerwony - pomniejszony\nZielony - normalny\nNiebieski - powiększony\nSzary - nie jest obiektem", -- scaler
		"Włącz lub wyłącz kolizję.\n\n\n\n\nZnaczenie kolorów:\nBiały - włączone\nNiebieski - wyłączone", -- collisions
	}
	modeEditDefaultText = { "ID lub nazwa pojazdu", "0-255", "skala > 0", "Włącz lub wyłącz" }
	modeEditText = modeEditDefaultText
	modeButtonsText = {
		{ "Podaj ID", "Stwórz" }, -- creator
		{ "Podaj widzialność", "Ustaw widzialność" }, -- alpha
		{ "Podaj skalę", "Ustaw skalę" }, -- scaler
		{ "Włącz", "Wyłącz" } -- collisions
	}
end

-----------------
--creating GUI --
-----------------

do -- GUI creating funcs
	g_Window = {}
	g_Button = {}
	g_SideButton = {}
	g_Checkbox = {}
	g_Label = {}
	g_Edit = {}
	g_OffsetsEdit = {}
	g_OffsetsRadio = {}
	g_Radio = {}
	
	local screenX, screenY = guiGetScreenSize ()

	-- main window
	g_Window [ 1 ] = guiCreateWindow ( screenX - 522, ( screenY - 396 ) / 2, 522, 396, "Panel Przyczepień Pojazdu 2.1 autorstwa Jamszy", false ) 
	g_Button [ 1 ] = guiCreateButton ( 0.2797, 0.6136, 0.0747, 0.0556, "+", true, g_Window [ 1 ] ) 
	g_Button [ 2 ] = guiCreateButton ( 0.3697, 0.6136, 0.0747, 0.0556, "—", true, g_Window [ 1 ] ) 
	g_Button [ 3 ] = guiCreateButton ( 0.0172, 0.0631, 0.1207, 0.0682, "<<<", true, g_Window [ 1 ] ) 
	g_Button [ 4 ] = guiCreateButton ( 0.0172, 0.9091, 0.1207, 0.0682, "Zamknij", true, g_Window [ 1 ] ) 
	g_Button [ 5 ] = guiCreateButton ( 0.3257, 0.9091, 0.1188, 0.0682, "Odśwież", true, g_Window [ 1 ] ) 
	g_Button [ 6 ] = guiCreateButton ( 0.3257, 0.7096, 0.1188, 0.0682, "Zniszcz", true, g_Window [ 1 ] ) 
	g_Button [ 7 ] = guiCreateButton ( 0.3238, 0.8081, 0.1188, 0.0682, "Odczep", true, g_Window [ 1 ] ) 
	g_Button [ 8 ] = guiCreateButton ( 0.1533, 0.7096, 0.1628, 0.0682, "Kopiuj offsety", true, g_Window [ 1 ] ) 
	g_Button [ 9 ] = guiCreateButton ( 0.1533, 0.8081, 0.1628, 0.0682, "Zaznacz myszką", true, g_Window [ 1 ] ) 
	g_Checkbox.x = guiCreateCheckBox ( 0.0766, 0.5328, 0.0307, 0.0429, "", false, true, g_Window [ 1 ] ) 
	g_Checkbox.y = guiCreateCheckBox ( 0.0766, 0.5758, 0.0307, 0.0429, "", false, true, g_Window [ 1 ] ) 
	g_Checkbox.z = guiCreateCheckBox ( 0.0766, 0.6187, 0.0307, 0.0429, "", false, true, g_Window [ 1 ] ) 
	g_RefreshCheckbox = guiCreateCheckBox ( 0.1533, 0.9091, 0.0287, 0.0682, "", false, true, g_Window [ 1 ] )
	g_Label [ 1 ] = guiCreateLabel ( 0.0766, 0.0631, 0.3678, 0.0657, "Ustaw offsety", true, g_Window [ 1 ] ) 
	g_Label [ 2 ] = guiCreateLabel ( 0.0766, 0.1288, 0.1782, 0.0556, "Pozycja", true, g_Window [ 1 ] ) 
	g_Label [ 3 ] = guiCreateLabel ( 0.2644, 0.1288, 0.1801, 0.0556, "Obrót", true, g_Window [ 1 ] ) 
	g_Label [ 4 ] = guiCreateLabel ( 0.0096, 0.1843, 0.067, 0.0682, "X", true, g_Window [ 1 ] ) 
	g_Label [ 5 ] = guiCreateLabel ( 0.0096, 0.2652, 0.067, 0.0682, "Y", true, g_Window [ 1 ] ) 
	g_Label [ 6 ] = guiCreateLabel ( 0.0096, 0.346, 0.067, 0.0682, "Z", true, g_Window [ 1 ] ) 
	g_Label [ 7 ] = guiCreateLabel ( 0.0096, 0.4268, 0.433, 0.0278, "——————————————————————————————", true, g_Window [ 1 ] ) 
	g_Label [ 8 ] = guiCreateLabel ( 0.0766, 0.4672, 0.3123, 0.0657, "Dodawanie offsetów", true, g_Window [ 1 ] ) 
	g_Label [ 9 ] = guiCreateLabel ( 0.0096, 0.5328, 0.067, 0.0429, "X", true, g_Window [ 1 ] ) 
	g_Label [ 10 ] = guiCreateLabel ( 0.0096, 0.5758, 0.067, 0.0429, "Y", true, g_Window [ 1 ] ) 
	g_Label [ 11 ] = guiCreateLabel ( 0.0096, 0.6187, 0.067, 0.0429, "Z", true, g_Window [ 1 ] ) 
	g_Label [ 12 ] = guiCreateLabel ( 0.1169, 0.5455, 0.1111, 0.0556, "Pozycja", true, g_Window [ 1 ] ) 
	g_Label [ 13 ] = guiCreateLabel ( 0.1169, 0.6136, 0.1111, 0.0556, "Obrót", true, g_Window [ 1 ] ) 
	g_Label [ 14 ] = guiCreateLabel ( 0.0115, 0.6692, 0.433, 0.0278, "——————————————————————————————", true, g_Window [ 1 ] ) 
	g_Label [ 15 ] = guiCreateLabel ( 0.1820, 0.9091, 0.1341, 0.0682, "AutoOdśw.", true, g_Window [ 1 ] )
	g_Edit [ 1 ] = guiCreateEdit ( 0.2797, 0.5328, 0.1648, 0.0682, "0.1", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.x = guiCreateEdit ( 0.0766, 0.1843, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.y = guiCreateEdit ( 0.0766, 0.2652, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.z = guiCreateEdit ( 0.0766, 0.346, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.rx = guiCreateEdit ( 0.2644, 0.1843, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.ry = guiCreateEdit ( 0.2644, 0.2652, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsEdit.rz = guiCreateEdit ( 0.2644, 0.346, 0.1782, 0.0682, "0", true, g_Window [ 1 ] ) 
	g_OffsetsRadio.pos = guiCreateRadioButton ( 0.2375, 0.5455, 0.0326, 0.0556, "", true, g_Window [ 1 ] ) 
	g_OffsetsRadio.rot = guiCreateRadioButton ( 0.2375, 0.6136, 0.0326, 0.0556, "", true, g_Window [ 1 ] ) 
	g_Grid = guiCreateGridList ( 0.454, 0.0606, 0.5287, 0.9167, true, g_Window [ 1 ] ) 

	guiCheckBoxSetSelected ( g_Checkbox.y , true ) 
	for i = 1, 15 do
		guiLabelSetHorizontalAlign ( g_Label [ i ] , "center" ) 
		guiLabelSetVerticalAlign ( g_Label [ i ] , "center" ) 
	end
	guiRadioButtonSetSelected ( g_OffsetsRadio.pos , true ) 
	guiGridListSetSortingEnabled ( g_Grid, false )
	guiGridListSetSelectionMode ( g_Grid , 2 ) 
	guiGridListAddColumn ( g_Grid, "Elementy", 0.85 )

	-- side window
	g_Window [ 2 ] = guiCreateWindow ( screenX - 522 - 170, ( screenY - 396 ) / 2, 170, 396, "Dodatkowe funkcje", false ) 
	g_SideButton.left = guiCreateButton ( 0.0529, 0.5934, 0.4, 0.0758, modeButtonsText [ 1 ] [ 1 ], true, g_Window [ 2 ] ) 
	g_SideButton.right = guiCreateButton ( 0.5471, 0.5934, 0.4, 0.0758, modeButtonsText [ 1 ] [ 2 ], true, g_Window [ 2 ] ) 
	g_Label [ 16 ] = guiCreateLabel ( 0.1765, 0.0606, 0.7882, 0.0707, "Stwarzacz", true, g_Window [ 2 ] ) 
	g_Label [ 17 ] = guiCreateLabel ( 0.1765, 0.1313, 0.7882, 0.0707, "Ustawianie widoczności", true, g_Window [ 2 ] ) 
	g_Label [ 18 ] = guiCreateLabel ( 0.1765, 0.202, 0.7882, 0.0707, "Skalowanie", true, g_Window [ 2 ] ) 
	g_Label [ 19 ] = guiCreateLabel ( 0.1765, 0.2727, 0.7882, 0.0707, "Przełącznik kolizji", true, g_Window [ 2 ] ) 
	--g_Label [ 20 ] = guiCreateLabel ( 0.1765, 0.3434, 0.7882, 0.0707, "Element Marker", true, g_Window [ 2 ] ) 
	--g_Label [ 21 ] = guiCreateLabel ( 0.1765, 0.4141, 0.7882, 0.0707, "Outputter", true, g_Window [ 2 ] ) 
	g_Label [ 20 ] = guiCreateLabel ( 0.0176, 0.66, 0.9294, 0.0278, "———————————————", true, g_Window [ 2 ] ) 
	g_SideLabel = guiCreateLabel ( 0.045, 0.68, 0.9, 0.3, modeLabelText [ 1 ], true, g_Window [ 2 ] ) 
	g_SideEdit = guiCreateEdit ( 0.0529, 0.5101, 0.8941, 0.0707, modeEditText [ 1 ], true, g_Window [ 2 ] ) 
	g_Radio [ 1 ] = guiCreateRadioButton ( 0.0529, 0.0606, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- creator
	g_Radio [ 2 ] = guiCreateRadioButton ( 0.0529, 0.1313, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- alpha
	g_Radio [ 3 ] = guiCreateRadioButton ( 0.0529, 0.202, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- scaler
	g_Radio [ 4 ] = guiCreateRadioButton ( 0.0529, 0.2727, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- collisions
	--g_Radio [ 5 ] = guiCreateRadioButton ( 0.0529, 0.3434, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- element marker
	--g_Radio [ 6 ] = guiCreateRadioButton ( 0.0529, 0.4141, 0.0941, 0.0707, "", true, g_Window [ 2 ] ) -- outputter
	
	for i = 16, 20 do
		guiLabelSetVerticalAlign ( g_Label [ i ], "center" )
		guiLabelSetHorizontalAlign ( g_Label [ i ], "left", true )
	end
	guiLabelSetHorizontalAlign ( g_SideLabel, "left", true )
	guiRadioButtonSetSelected ( g_Radio [ 1 ] , true ) 
	
	-- preparations
	for k, v in ipairs ( g_Window ) do
		guiSetVisible ( v, false )
		guiWindowSetSizable ( v, false )
		guiWindowSetMovable ( v, false )
	end	
end

-------------------
-- operating GUI --
-------------------

function g_OffsetsEditUpdate () -- done
	for k, v in pairs ( g_OffsetsEdit ) do
		local number = commaToDot ( guiGetText ( v ) ) or 0
		posrot [ k ] = number
		guiSetText ( v,  number )
	end
end

function g_EditHandler ( guiElement ) -- done
	if guiElement == g_Edit [ 1 ] then
		local posbool = guiRadioButtonGetSelected ( g_OffsetsRadio.pos )
		local number = commaToDot ( guiGetText ( guiElement ) )
		if posbool then
			pos = math.round ( number, 2 ) or 0.1
		else
			rot = math.round ( number ) or 15
		end
	elseif guiElement ~= g_SideEdit then
		local bool = false
		for k, v in pairs ( g_OffsetsEdit ) do
			if v == guiElement then
				bool = true
				number = math.round ( commaToDot ( guiGetText ( guiElement ) ), 3 ) or 0
				if number then
					posrot [ k ] = number
				end
			else
				local rounded = math.round ( commaToDot ( guiGetText ( v ) ), 3 ) or 0
				posrot [ k ] = rounded
				guiSetText ( v, rounded )
			end
		end
		if bool and theElement then
			local x, y, z, rx, ry, rz = unpack ( posrot )
			callServerFunction ( "setElementAttachedOffsets", theElement, posrot.x, posrot.y, posrot.z, posrot.rx, posrot.ry, posrot.rz )
		end
	end
end

function g_PreShower () -- done
	g_Shower ( not guiGetVisible ( g_Window [ 1 ] ) )
end

function g_Shower ( bool ) -- done
	if bool == nil then
		bool = not guiGetVisible ( g_Window [ 1 ] )
	end
	guiSetVisible ( g_Window [ 1 ], bool )
	showCursor ( bool, true )
	if bool == true and isSideShown then
		g_SideShower ( true )
		for i, v in ipairs ( g_Radio ) do
			if guiRadioButtonGetSelected ( v ) then
				mode = i
				break
			end
		end
	end
	if bool == false then
		guiSetVisible ( g_Window [ 2 ], false )
		guiSetText ( g_Button [ 3 ], "<<<" )
		mode = 0
	end
	if not enabled then
		setCameraClip ( false, false )
		enabled = true
	end
	if bool == false and copyBool then
		copyBool = false
		outputChatBox ( "Kopiowanie offsetów #9696ffanulowane#6464ff, ponieważ zamknięto okienko #9696ffP3#6464ff!", 100, 100, 255, true )
		guiSetText ( g_Button [ 11 ], "Copy Offsets" )
	end
	if bool == false and mouseBool then
		mouseBool = false
		outputChatBox ( "Zaznaczanie myszką #9696ffanulowane#6464ff, ponieważ zamknięto okienko #9696ffP3#6464ff!", 100, 100, 255, true )
		guiSetText ( g_Button [ 8 ], "Mouse Select" )
	end
	guiSetInputMode ( "no_binds_when_editing" ) -- just in case
end

function g_SideShower ( bool ) -- done
	local data = { [ true ] = ">>>", [ false ] = "<<<" }
	if bool == nil then
		bool = not guiGetVisible ( g_Window [ 2 ] )
	end
	guiSetVisible ( g_Window [ 2 ], bool )
	guiSetText ( g_Button [ 3 ], data [ bool ] )
	isSideShown = bool
	if bool then
		for i, v in ipairs ( g_Radio ) do
			if guiRadioButtonGetSelected ( v ) then
				mode = i
				break
			end
		end
	else
		mode = 0
	end
end

function g_AddOffsets ( multiplier ) -- done
	if theElement then
		local data = { [ false ] = 0, [ true ] = 1 }
		local rot = data [ guiRadioButtonGetSelected ( g_OffsetsRadio.rot ) ]
		local pos = data [ guiRadioButtonGetSelected ( g_OffsetsRadio.pos ) ]
		if rot or pos then
			local diff = {} 
			diff.n = commaToDot ( guiGetText ( g_Edit [ 1 ] ) )
			if not diff.n then
				if pos then
					diff.n = 0.1
				else
					diff.n = 15
				end
				guiSetText ( g_Edit [ 1 ], diff.n )
			end
			g_OffsetsEditUpdate ()
			local bool = false
			for k, v in pairs ( g_Checkbox ) do
				if guiCheckBoxGetSelected ( v ) then
					diff [ k ] = 1
					bool = true
				else
					diff [ k ] = 0
				end
			end
			if bool then
				local x, y, z, rx, ry, rz = getElementAttachedOffsets ( theElement )
				local nx = math.round ( x + multiplier * diff.n * diff.x * pos, 3 )
				local ny = math.round ( y + multiplier * diff.n * diff.y * pos, 3 )
				local nz = math.round ( z + multiplier * diff.n * diff.z * pos, 3 )
				local nrx = math.round ( rx + multiplier * diff.n * diff.x * rot, 3 )
				local nry = math.round ( ry + multiplier * diff.n * diff.y * rot, 3 )
				local nrz = math.round ( rz + multiplier * diff.n * diff.z * rot, 3 )
				guiSetText ( g_OffsetsEdit.x, nx )
				guiSetText ( g_OffsetsEdit.y, ny )
				guiSetText ( g_OffsetsEdit.z, nz )
				guiSetText ( g_OffsetsEdit.rx, nrx )
				guiSetText ( g_OffsetsEdit.ry, nry )
				guiSetText ( g_OffsetsEdit.rz, nrz )
				callServerFunction ( "setElementAttachedOffsets", theElement, nx, ny, nz, nrx, nry, nrz )
				g_OffsetsEditUpdate ()
			else
				outputChatBox ( "Zaznacz przynajmniej jedną z osi #9696ffX#6464ff, #9696ffY#6464ff i/lub #9696ffZ#6464ff!", 100, 100, 255, true )
			end
		else
			outputChatBox ( "Zaznacz typ zmiany: #9696ffpozycji#6464ff lub #9696ffobrotu#6464ff!", 100, 100, 255, true )
		end
	else
		announce ( "noElem" )
	end
end

function g_ClickHandler ()
	if source == g_Grid then -- choose theElement from gridList ( and copy offsets to it if copying is enabled )
		local row, column = guiGridListGetSelectedItem ( g_Grid )
		if row >= 0 then
			theElement = guiGridListGetItemData ( g_Grid, row, 1 )
			if isElement ( theElement ) and getElementAttachedTo ( theElement ) == theVehicle then
				theElementName = guiGridListGetItemText ( g_Grid, row, 1 ) or "Unknown Element"
				if copyBool then
					if copyElementName then
						outputChatBox ( "Pomyślnie skopiowano offsety z #9696ff" .. copyElementName .. "#6464ff do #9696ff" .. theElementName .. "#6464ff.", 100, 100, 255, true )
						copyElementName = false
					else
						outputChatBox ( "Pomyślnie ustawiono offsety elementu #9696ff" .. theElementName .. "#6464ff.", 100, 100, 255, true )
					end
					copyBool = false
					guiSetText ( g_Button [ 8 ], "Kopiuj offsety" )
				else
					local x, y, z, rx, ry, rz = getElementAttachedOffsets ( theElement )
					guiSetText ( g_OffsetsEdit.x, x )
					guiSetText ( g_OffsetsEdit.y, y )
					guiSetText ( g_OffsetsEdit.z, z )
					guiSetText ( g_OffsetsEdit.rx, rx )
					guiSetText ( g_OffsetsEdit.ry, ry )
					guiSetText ( g_OffsetsEdit.rz, rz )
					--[[for k, v in pairs ( g_OffsetsEdit ) do
						guiEditSetCaretIndex ( v, 0 )
					end]]
				end
				g_OffsetsEditUpdate ()
				callServerFunction ( "setElementAttachedOffsets", theElement, posrot.x, posrot.y, posrot.z, posrot.rx, posrot.ry, posrot.rz )
			else
				theElement = nil
				outputChatBox ( "Zaznaczony #9696ffelement#6464ff nie istnieje lub nie jest przyczepiony do #9696ffpojazdu#6464ff. Proszę #9696ffodświeżyć#6464ff listę.", 100, 100, 255, true )
			end
		else
			if copyBool then
				outputChatBox ( "Proszę zaznaczyć #9696ffelement#6464ff do skopiowania offsetów lub kliknąć przycisk #9696ffAnuluj#6464ff by anulować kopiowanie.", 100, 100, 255, true )
			else
				theElement = nil
				theElementName = nil
				for k, v in pairs ( g_OffsetsEdit ) do
					guiSetText ( v, 0 )
					--guiEditSetCaretIndex ( v, 0 )
				end
				g_OffsetsEditUpdate ()
			end
		end
	elseif source == g_RefreshCheckbox then -- autorefresh	
		autoRefreshBool = guiCheckBoxGetSelected ( g_RefreshCheckbox )
	elseif source == g_Button [ 1 ] then -- add
		g_AddOffsets ( 1 )
	elseif source == g_Button [ 2 ] then -- substract
		g_AddOffsets ( - 1 )
	elseif source == g_Button [ 3 ] then -- show/hide sideWindow
		g_SideShower ( not guiGetVisible ( g_Window [ 2 ] ) )
	elseif source == g_Button [ 4 ] then -- show/hide GUI
		g_Shower ( not guiGetVisible ( g_Window [ 1 ] ) )
	elseif source == g_Button [ 5 ] then -- refresh grid
		for k, v in pairs ( g_OffsetsEdit ) do
			guiSetText ( v, 0 )
			guiEditSetCaretIndex ( v, 0 )
		end
		g_OffsetsEditUpdate ()
		g_GridClean ()
		if theVehicle then
			g_GridUpdate ()
		else
			announce ( "noVeh" )
		end
	elseif source == g_Button [ 6 ] then -- destroy elem
		if theElement then
			callServerFunction ( "P3destroy", thePlayer, theElement, theElementName )
		else
			announce ( "noElem" )
		end
	elseif source == g_Button [ 7 ] then -- detach element
		if theElement then
			callServerFunction ( "P3detach", thePlayer, theElement, theElementName )
		else
			announce ( "noElem" )
		end
	elseif source == g_Button [ 8 ] then -- copy offsets
		if theVehicle then
			if copyBool then
				outputChatBox ( "Kopiowanie #9696ffanulowane#6464ff!", 100, 100, 255, true )
				guiSetText ( g_Button [ 8 ], "Kopiuj offsety" )
			else
				g_OffsetsEditUpdate ()
				outputChatBox ( "Zaznacz #9696ffelement#6464ff z listy by ustawić offsety lub kliknij przycisk #9696ffAnuluj#6464ff by anulować kopiowanie.", 100, 100, 255, true )
				guiSetText ( g_Button [ 8 ], "Anuluj" )
				local row, column = guiGridListGetSelectedItem ( g_Grid )
				if row >= 0 then
					copyElementName = guiGridListGetItemText ( g_Grid, row, column )
				else
					copyElementName = false
				end
			end
			copyBool = not copyBool
		else
			announce ( "noVeh" )
		end
	elseif source == g_Button [ 9 ] then -- mouse select
		if theVehicle then
			if mouseBool then
				outputChatBox ( "Zaznaczanie myszką #9696ffanulowane#6464ff!", 100, 100, 255, true )
				guiSetText ( g_Button [ 9 ], "Zaznacz myszką" )
				mouseBool = false
			else
				local attachedElements = getAttachedElements ( theVehicle )
				if #attachedElements >= 1 then
					outputChatBox ( "Wybierz #9696ffelement#6464ff, klikając na nim myszką lub kliknij przycisk #9696ffAnuluj#6464ff by anulować zaznaczanie myszką.", 100, 100, 255, true )
					guiSetText ( g_Button [ 9 ], "Anuluj" )
					mouseBool = true
				else
					outputChatBox ( "Nie ma #9696ffnic#6464ff przyczepionego do #9696ffpojazdu#6464ff.", 100, 100, 255, true )
				end
			end
		else
			announce ( "noVeh" )
		end
	elseif source == g_Button [ 10 ] then -- console output shower
		g_OutputShower ( false )
	elseif source == g_OffsetsRadio.rot then -- rot diff
		guiSetText ( g_Edit [ 1 ], rot )
	elseif source == g_OffsetsRadio.pos then -- pos diff
		guiSetText ( g_Edit [ 1 ], pos )
	elseif source == g_SideButton.left then
		if mode == 1 then -- creator / getid
			if theElement then
				guiSetText ( g_SideEdit, getElementModel ( theElement ) or "Błąd" )
			else
				announce ( "noElem" )
			end	
		elseif mode == 2 then -- alpha setter / getalpha
			if theElement then
				guiSetText ( g_SideEdit, getElementAlpha ( theElement ) or "Błąd" )
			else
				announce ( "noElem" )
			end	
		elseif mode == 3 then -- scaler / getscale
			if theElement then
				if getElementType ( theElement ) == "object" then
					guiSetText ( g_SideEdit, getObjectScale ( theElement ) or "Błąd" )
				else
					outputChatBox ( "Wybrany element nie jest #9696ffobiektem#6464ff!", 100, 100, 255, true )
				end
			else
				announce ( "noElem" )
			end
		elseif mode == 4 then -- collisions / true
			if theElement then
				callServerFunction ( "P3collisionToggle", thePlayer, theElement, theElementName, true )
			else
				announce ( "noElem" )
			end	
		--[[elseif mode == 5 then -- marker / getflag
			if theElement then
				guiSetText ( g_SideEdit, getElementData ( theElement, "P3mark" ) or "No elementData set." )
			else
				announce ( "noElem" )
			end]]
		end
	elseif source == g_SideButton.right then
		if mode == 1 then -- creator / create by id
			if theVehicle then
				local id = guiGetText ( g_SideEdit )
				if string.len ( id ) > 0 then
					callServerFunction ( "P3create", thePlayer, theVehicle, id )
				else
					outputChatBox ( "Nie podano #9696ffID/nazwy auta#6464ff!", 100, 100, 255, true )
					guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
				end
			else
				announce ( "noVeh" )
			end
		elseif mode == 2 then -- alpha setter / setalpha
			if theElement then
				local alpha = commaToDot ( guiGetText ( g_SideEdit ) )
				if type ( alpha ) == "number" and alpha >= 0 and alpha <= 255 then
					callServerFunction ( "P3visibilityToggle", thePlayer, theElement, theElementName, alpha )
				else
					outputChatBox ( "Podano zły #9696ffnumer#6464ff!", 100, 100, 255, true )
					guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
				end
			else
				announce ( "noElem" )
			end
		elseif mode == 3 then -- scaler / setscale
			if theElement then
				if getElementType ( theElement ) == "object" then
					local factor = commaToDot ( guiGetText ( g_SideEdit ) )
					if factor and factor >= 0.01 and factor <= 10 then
						callServerFunction ( "P3scale", thePlayer, theElement, theElementName, factor )
					else
						outputChatBox ( "Podano zły #9696ffnumer#6464ff!", 100, 100, 255, true )
						guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
					end
				else
					outputChatBox ( "Wybrany element nie jest #9696ffobiektem#6464ff!", 100, 100, 255, true )
				end
			else
				announce ( "noElem" )
			end
		elseif mode == 4 then -- collisions / false
			if theElement then
				callServerFunction ( "P3collisionToggle", thePlayer, theElement, theElementName, false )
			else
				announce ( "noElem" )
			end
		--[[elseif mode == 5 then -- marker / setflag
			if theElement then
				local flag = guiGetText ( g_SideEdit )
				if string.len ( flag ) > 0 and flag ~= "ElementData flag" then
					setElementData ( theElement, "P3mark", flag )
					outputChatBox ( "Set element data of #9696ff" .. theElementName .. "#6464ff using flag #9696ff" .. flag .. "#6464ff.", 100, 100, 255, true )
				else
					outputChatBox ( "Please pass a #9696ffflag#6464ff to be set as elementData!", 100, 100, 255, true )
					guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
				end
			else
				announce ( "noElem" )
			end
		elseif mode == 6 then -- outputter / output
			if theVehicle then
				local acceptedTypes = { "vehicle", "object" }
				local outputTable = {}
				local var = guiGetText ( g_SideEdit )
				local flag = string.gsub ( var, "[^%w]", "" )
				if string.len ( flag ) == 0 or var ~= flag then
					outputTable [ 1 ] = "local mainVehicle = createVehicle ( " .. getElementModel ( theVehicle ) .. ", 0, 0, 0 )" 
					outputTable [ 2 ] = "setVehicleDamageProof ( mainVehicle, true )"
					flag = "mainVehicle"
					guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
				end
				for k, element in ipairs ( getAttachedElements ( theVehicle ) ) do
					local elementType = getElementType ( element )
					local bool
					for k, v in ipairs ( acceptedTypes ) do
						if elementType == v then
							bool = true
							break
						end
					end
					if bool then
						local model = getElementModel ( element )
						local elementTypeUpper = string.upper ( string.sub ( elementType, 1, 1 ) ) .. string.sub ( elementType, 2 )
						table.insert ( outputTable, "local element" .. k .. " = create" .. elementTypeUpper .. " ( " .. model .. ", 0, 0, 0 )" )
						table.insert ( outputTable, "attachElements ( element" .. k .. ", " .. flag .. " )" )
						if getElementCollisionsEnabled ( element ) == false then
							table.insert ( outputTable, "setElementCollisionsEnabled ( element" .. k .. ", false )" )
						end
						local alpha = getElementAlpha ( element )
						if alpha ~= 255 then
							table.insert ( outputTable, "setElementAlpha ( element" .. k .. ", " .. alpha .. " )" )
						end
						if elementType == "object" then
							local scale = getObjectScale ( element )
							if scale ~= 1 then
								table.insert ( outputTable, "setObjectScale ( element" .. k .. ", " .. scale .. " )" )
							end
						elseif elementType == "vehicle" then
							table.insert ( outputTable, "setVehicleDamageProof ( element" .. k .. ", true )" )
						end
					end
				end
				local outputString = table.concat ( outputTable, "\n" )
				guiSetText ( g_Memo, outputString )
				g_OutputShower ( true )
			else
				announce ( "noVeh" )
			end]]
		end
	else -- mode select
		for i, radioButton in ipairs ( g_Radio ) do
			if source == radioButton then
				modeEditText [ mode ] = guiGetText ( g_SideEdit ) or modeEditDefaultText [ mode ]
				mode = i
				if i == 4 then
					guiEditSetReadOnly ( g_SideEdit, true )
					guiSetText ( g_SideEdit, modeEditDefaultText [ mode ] )
				else
					guiEditSetReadOnly ( g_SideEdit, false )
				end
				--[[if i ~= 6 then
					g_OutputShower ( false )
				end]]
				guiSetText ( g_SideLabel, modeLabelText [ i ] ) 
				guiSetText ( g_SideEdit, modeEditText [ i ] )
				guiSetText ( g_SideButton.left, modeButtonsText [ i ] [ 1 ] )
				guiSetText ( g_SideButton.right, modeButtonsText [ i ] [ 2 ] )
				if theVehicle then
					g_GridUpdate ()
				end
				break
			end
		end
	end
end

function g_MouseClickHandler ( button, state, ax, ay, wx, wy, wz, element ) -- done
	if button == "left" and state == "up" and element then
		if mouseBool then
			if element then
				if getElementAttachedTo ( element ) == theVehicle then
					local rows = guiGridListGetRowCount ( g_Grid )
					if rows >= 0 then
						for row = 0, rows do
							if element == guiGridListGetItemData ( g_Grid, row, 1 ) then
								theElement = guiGridListGetItemData ( g_Grid, row, 1 )
								theElementName = guiGridListGetItemText ( g_Grid, row, 1 ) or ""
								local x, y, z, rx, ry, rz = getElementAttachedOffsets ( theElement )
								guiSetText ( g_OffsetsEdit.x, x )
								guiSetText ( g_OffsetsEdit.y, y )
								guiSetText ( g_OffsetsEdit.z, z )
								guiSetText ( g_OffsetsEdit.rx, rx )
								guiSetText ( g_OffsetsEdit.ry, ry )
								guiSetText ( g_OffsetsEdit.rz, rz )
								--[[for k, v in pairs ( g_OffsetsEdit ) do
									guiEditSetCaretIndex ( v, 0 )
								end]]
								g_OffsetsEditUpdate ()
								callServerFunction ( "setElementAttachedOffsets", theElement, x, y, z, rx, ry, rz )
								guiGridListSetSelectedItem ( g_Grid, row, 1 )
								outputChatBox ( "Wybrano #9696ff" .. theElementName .. "#6464ff.", 100, 100, 255, true )
								mouseBool = false
								guiSetText ( g_Button [ 9 ], "Zaznacz myszką" )
								return true
							end
						end
					end
				else
					outputChatBox ( "Wybrany #9696ffelement#6464ff nie jest przyczepiony do #9696ffpojazdu#6464ff!", 100, 100, 255, true )
				end
			else
				outputChatBox ( "Wybierz #9696ffelement#6464ff, klikając na nim myszką lub kliknij przycisk #9696ffAnuluj#6464ff by anulować zaznaczanie myszką.", 100, 100, 255, true )
			end
		end
	end
end

-------------
-- updates --
-------------

function g_SetColor ( element, row )
	local row = row
	if not row then
		for i = 0, guiGridListGetRowCount ( g_Grid ) do
			if guiGridListGetItemData ( g_Grid, i, 1 ) == element then
				row = i
				break
			end
		end
	end
	if not row then
		return
	end
	local r, g, b = 255, 255, 255
	if mode ~= 0 and mode ~= 1 then
		if mode == 2 then
			local alpha = getElementAlpha ( element )
			r, g, b = alpha, alpha, alpha * 9 / 17 + 120
		elseif mode == 3 then
			if getElementType ( element ) == "object" then
				local scale = getObjectScale ( element )
				if scale < 1 then
					r, g, b = 255, 50, 50
				elseif scale == 1 then
					r, g, b = 50, 255, 50
				else
					r, g, b = 50, 50, 255
				end
			else
				r, g, b = 50, 50, 50
			end
		elseif mode == 4 then
			if getElementCollisionsEnabled ( element ) == false then
				r, g, b = 120, 120, 255
			end
		end
	end
	guiGridListSetItemColor ( g_Grid, row, 1, r, g, b )
end

function g_SetName ( element, row )
	local row = row
	if not row then
		for i = 0, guiGridListGetRowCount ( g_Grid ) do
			if guiGridListGetItemData ( g_Grid, i, 1 ) == element then
				row = i
				break
			end
		end
	end
	if not row then
		return
	end
	local elementType = getElementType ( element )
	local rowText = ""
	if elementType == "object" then
		rowText = "Obiekt ID " .. getElementModel ( element )
	elseif elementType == "vehicle" then
		rowText = "Pojazd " .. getVehicleNameFromModel ( getElementModel ( element ) )
	elseif elementType == "ped" then
		rowText = "Ped " .. getElementModel ( element )
	elseif elementType == "marker" then
		rowText = getMarkerType ( element ) .. " marker"
	elseif elementType == "player" then
		rowText = "Gracz " .. getPlayerName ( element )
	end
	guiGridListSetItemText ( g_Grid, row, 1, rowText, false, false )
end

function g_AddToGridList ( element ) -- done
	table.insert ( gridListElements, element )
	local row = guiGridListAddRow ( g_Grid )
	g_SetName ( element, row )
	g_SetColor ( element, row )
	guiGridListSetItemData ( g_Grid, row, 1, element )
end

function g_GridUpdate () -- done
	if #gridListElements > 0 then -- erasing non-existent elements from gridlist and refreshing the old
		for g_key, g_element in ipairs ( gridListElements ) do
			for row = 0, guiGridListGetRowCount ( g_Grid ) do
				if guiGridListGetItemData ( g_Grid, row, 1 ) == g_element then
					if isElement ( g_element ) and getElementAttachedTo ( g_element ) == theVehicle then -- exists, refreshing
						g_SetName ( g_element, row )
						g_SetColor ( g_element, row )
					else -- doesn't exist, removing
						guiGridListRemoveRow ( g_Grid, row )
						table.remove ( gridListElements, g_key )
						if g_element == theElement then
							for k, v in pairs ( g_OffsetsEdit ) do
								guiSetText ( v, 0 )
							end
							g_OffsetsEditUpdate ()
						end
					end
				end
			end
		end
	end
	local attachedElements = getAttachedElements ( theVehicle )
	if attachedElements and #attachedElements > 0 then -- adding new elements
		for key, element in ipairs ( attachedElements ) do
			local isInGridList = false
			for g_key, g_element in ipairs ( gridListElements ) do
				if g_element == element then -- is in gridlist, not adding
					isInGridList = true
					break
				end
			end
			if isInGridList == false then -- isn't in gridlist, adding
				g_AddToGridList ( element )
			end
		end
	else
		g_GridClean ()
	end
end

function g_GridClean () -- done
	guiGridListClear ( g_Grid )
	gridListElements = {}
	theElement = nil
	theElementName = ""
	for k, v in pairs ( g_OffsetsEdit ) do
		guiSetText ( v, 0 )
	end
	g_OffsetsEditUpdate ()
end

function P3update () -- done
	if guiGetVisible ( g_Window [ 1 ] ) then
		theVehicle = getPedOccupiedVehicle ( thePlayer )
		if theVehicle then
			if autoRefreshBool then
				g_GridUpdate ()
			end
		else
			g_GridClean ()
		end
	end
end
setTimer ( P3update, 200, 0 )

--------------
-- handlers --
--------------

addEventHandler ( "onClientClick", root, g_MouseClickHandler )
addEventHandler ( "onClientGUIChanged", root, g_EditHandler )
--[[addEventHandler ( "onClientPlayerVehicleEnter", thePlayer, vehicleUpdate, false )
addEventHandler ( "onClientPlayerVehicleExit", thePlayer, vehicleUpdate, false )
addEventHandler ( "onClientPlayerWasted", thePlayer, vehicleUpdate, false )]]
addEventHandler ( "onClientGUIClick", root, g_ClickHandler )
addCommandHandler ( "p3", g_PreShower )
addCommandHandler ( "P3", g_PreShower )